package com.yenlien.traceyun.webase.dao;

import com.yenlien.traceyun.common.utils.LoggerUtil;
import com.yenlien.traceyun.webase.config.ApplicationContextConfig;
import org.hibernate.Session;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

/**
 * @author wangyang@3sqy.cn
 * @date 2017年11月14日
 * @Description:
 */
@NoRepositoryBean
public interface BaseJpaDao<T> extends JpaRepository<T, Serializable>, JpaSpecificationExecutor<T> {


    /**
     * sql原生查詢
     *
     * @param sql
     * @param clazz
     * @param <T>
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public <T> List<T> sqlQueryList(String sql, Class<T> clazz) {
        Session session = ApplicationContextConfig.getEntityManager().unwrap(org.hibernate.Session.class);
        NativeQuery query = session.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(new SqlResultTransformer(clazz));
        return query.getResultList();
    }

    /**
     * sql原生查詢
     *
     * @param sql
     * @param clazz
     * @return
     * @params <T>
     * @params params
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public <T> List<T> sqlQueryList(String sql, Class<T> clazz, Object[] params) {
        Session session = ApplicationContextConfig.getEntityManager().unwrap(org.hibernate.Session.class);

        NativeQuery query = session.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(new SqlResultTransformer(clazz));
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                query.setParameter(i + 1, params[i]);
            }
        }
        LoggerUtil.logInfo("sql:" + sql);
        return query.getResultList();
    }

    /**
     * sql原生查詢
     *
     * @param sql
     * @param clazz 必须有entity注解
     * @param <T>
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public <T> List<T> sqlQueryEntityList(String sql, Class<T> clazz) {
        Query query = ApplicationContextConfig.getEntityManager().createNativeQuery(sql, clazz);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(clazz));
        return query.getResultList();
    }

    /**
     * sql原生查詢
     *
     * @param sql
     * @param clazz  必须有entity注解
     * @param <T>
     * @param params
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public <T> List<T> sqlQueryEntityList(String sql, Class<T> clazz, String[] params) {
        Query query = ApplicationContextConfig.getEntityManager().createNativeQuery(sql, clazz);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(clazz));
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                query.setParameter(i + 1, params[i]);
            }
        }
        return query.getResultList();
    }

    /**
     * sql原生查詢
     *
     * @param sql
     * @param
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public List<Map<String, Object>> sqlQueryMap(String sql) {
        Query query = ApplicationContextConfig.getEntityManager().createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getResultList();
    }

    /**
     * sql原生查詢
     *
     * @param sql
     * @param clazz
     * @param <T>
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public <T> T sqlQueryOne(String sql, Class<T> clazz, String[] params) {
        Session session = ApplicationContextConfig.getEntityManager().unwrap(org.hibernate.Session.class);
        NativeQuery query = session.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(new SqlResultTransformer(clazz));
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                query.setParameter(i + 1, params[i]);
            }
        }
        return (T) query.getSingleResult();
    }

    /**
     * sql原生查詢
     *
     * @param sql
     * @param clazz
     * @param <T>
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    default public <T> T sqlQueryOne(String sql, Class<T> clazz) {
        Session session = ApplicationContextConfig.getEntityManager().unwrap(org.hibernate.Session.class);
        NativeQuery query = session.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(new SqlResultTransformer(clazz));
        return (T) query.getSingleResult();
    }
}
